﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Windows;
using System.Windows.Input;
using System.Xml.Linq;
using Rxx.Labs.Properties;

namespace Rxx.Labs.Reactive.UI
{
	[DisplayName("Routed Event Bindings")]
	[Description("Binding UI events to handlers with the EventSubscription trigger.")]
	public partial class EventSubscriptionTriggerLab : BaseLab, INotifyPropertyChanged
	{
		public IEnumerable<XElement> Items
		{
			get
			{
				return Enumerable.Range(1, 5).Select(value => XElement.Parse(
					string.Format(CultureInfo.CurrentCulture, Text.EventSubscriptionTriggerLabXml, value)));
			}
		}

		public Subject<EventPattern<RoutedEventArgs>> ShowItemPreview
		{
			get
			{
				return showItemPreview;
			}
		}

		public ICommand ShowItemDetails
		{
			get
			{
				return showItemDetails;
			}
		}

		public EventHandler ResetItemDetails
		{
			get
			{
				return OnResetItemDetails;
			}
		}

		public string Preview
		{
			get
			{
				return preview;
			}
			private set
			{
				if (preview != value)
				{
					preview = value;

					OnPropertyChanged(new PropertyChangedEventArgs("Preview"));
				}
			}
		}

		public string Details
		{
			get
			{
				return details;
			}
			private set
			{
				if (details != value)
				{
					details = value;

					OnPropertyChanged(new PropertyChangedEventArgs("Details"));
				}
			}
		}

		private readonly Subject<EventPattern<RoutedEventArgs>> showItemPreview = new Subject<EventPattern<RoutedEventArgs>>();
		private readonly CommandSubject showItemDetails = new CommandSubject();
		private string preview = Instructions.EventSubscriptionTriggerLabMouseOver;
		private string details = Instructions.EventSubscriptionTriggerLabDoubleClick;

		public EventSubscriptionTriggerLab()
		{
			InitializeComponent();
		}

		protected override IEnumerable<IDisposable> Main()
		{
			TraceLine(Instructions.EventSubscriptionTriggerLabMouseOver);
			TraceLine(Instructions.EventSubscriptionTriggerLabDoubleClick);

			yield return showItemPreview
				.Select(e => ((FrameworkElement) e.EventArgs.OriginalSource).DataContext as XElement)
				.DistinctUntilChanged()
				.Subscribe(item => Preview =
					item == null
					? Instructions.EventSubscriptionTriggerLabMouseOver
					: item.Element("preview").Value);

#if SILVERLIGHT
			// http://msdn.microsoft.com/en-us/library/cc189029(v=vs.95).aspx#doubleclick
			var detailsQuery =
				(from first in showItemDetails.Take(1)
				 from second in showItemDetails.Timeout(TimeSpan.FromMilliseconds(200), Observable.Empty<object>())
				 let firstEvent = (EventPattern<MouseButtonEventArgs>) first
				 let secondEvent = (EventPattern<MouseButtonEventArgs>) second
				 let firstData = ((FrameworkElement) firstEvent.EventArgs.OriginalSource).DataContext
				 let secondData = ((FrameworkElement) secondEvent.EventArgs.OriginalSource).DataContext
				 where firstData == secondData
				 select second)
				 .Take(1)
				 .Repeat();
#else
			var detailsQuery = showItemDetails;
#endif

			yield return detailsQuery
				.Select(e => (EventPattern<MouseButtonEventArgs>) e)
				.Select(e => ((FrameworkElement) e.EventArgs.OriginalSource).DataContext as XElement)
				.Where(item => item != null)
				.Subscribe(item => Details = item.Element("details").Value);
		}

		private void OnResetItemDetails(object sender, EventArgs e)
		{
			Details = Instructions.EventSubscriptionTriggerLabDoubleClick;
		}

		public event PropertyChangedEventHandler PropertyChanged;

		private void OnPropertyChanged(PropertyChangedEventArgs e)
		{
			var handler = PropertyChanged;

			if (handler != null)
			{
				handler(this, e);
			}
		}
	}
}